package com.hitqz.robot.biz.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hitqz.robot.api.business.enums.WorkStatusEnum;
import com.hitqz.robot.api.common.dto.warning.AddWarningDto;
import com.hitqz.robot.api.common.entity.MapArea;
import com.hitqz.robot.api.common.entity.MapAreaPos;
import com.hitqz.robot.api.common.entity.Robot;
import com.hitqz.robot.api.common.entity.RobotMapPos;
import com.hitqz.robot.biz.business.dispatch.DispatchService;
import com.hitqz.robot.biz.business.model.Point;
import com.hitqz.robot.biz.business.util.CalculateUtil;
import com.hitqz.robot.biz.service.*;
import com.hitqz.robot.driver.model.IRobotPosDto;
import com.hitqz.robot.driver.parent.RobotDriverService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author xupkun
 * @date 2024/7/31
 */
@Service
@AllArgsConstructor
@Slf4j
public class BusinessServiceImpl implements BusinessService {

    private final RobotMapPosService robotMapPosService;
    private final RobotDriverService robotDriverService;
    private final RobotService robotService;
    private final MapAreaService mapAreaService;
    private final MapAreaActionService mapAreaActionService;
    private final AreaActionService areaActionService;
    private final MapAreaPosService mapAreaPosService;

    private final DispatchService dispatchService;


    @Override
    public boolean goCharge(boolean webCtrl, boolean forceCharge) {
        synchronized (this) {
            Robot robot = robotService.getDefaultRobot();
            if (robot == null) {
                log.error("Robot is null, cannot proceed with charging.");
                return false;
            }

            IRobotPosDto iRobotPosDto = robotDriverService.getWebPos();
            int chargeThreshold = Optional.ofNullable(robot.getChargeThreshold()).orElse(20);

            if (iRobotPosDto == null || chargeThreshold < 0) {
                return false;
            }

            // 简化条件表达式
            boolean shouldCharge = (iRobotPosDto.getBatteryLevel() > 0 &&iRobotPosDto.getBatteryLevel() <= chargeThreshold) || webCtrl;

            if (shouldCharge) {
                if (!forceCharge && !robot.getWorkStatus().equals(WorkStatusEnum.FREE.getCode())) {
                    log.info("Robot is not free, cannot charge: {}, {}", robot.getWorkStatus(), WorkStatusEnum.CMD_ROBOT_STATUS.get(robot.getWorkStatus()));
                    return false;
                }

                log.info("Battery level low: {} (threshold: {}) - Web control: {}", iRobotPosDto.getBatteryLevel(), chargeThreshold, webCtrl);

                if (!iRobotPosDto.isCharging()) {
                    List<MapArea> mapAreas = mapAreaService.findMapAreaActions("charging")
                            .stream()
                            .filter(t -> t.getStatus() == 1 && t.getMapCode().equals(robot.getMapCode()))
                            .toList();

                    if (mapAreas.isEmpty()) {
                        log.info("No charging area configured for the current map.");
                        return false;
                    }

                    // Find the closest charging position
                    List<RobotMapPos> mapPos = robotMapPosService.list(Wrappers.<RobotMapPos>lambdaQuery().eq(RobotMapPos::getMapCode, robot.getMapCode()));
                    AtomicReference<RobotMapPos> chargingPos = new AtomicReference<>();

                    for (MapArea mapArea : mapAreas) {
                        List<MapAreaPos> mapAreaPosList = mapAreaPosService.list(Wrappers.<MapAreaPos>lambdaQuery()
                                .eq(MapAreaPos::getAreaId, mapArea.getId()));

                        if (CollectionUtil.isEmpty(mapAreaPosList) || mapAreaPosList.size() < 4) {
                            log.warn("Map area not properly configured: {}", mapArea.getId());
                            continue;
                        }

                        List<Point> polygon = mapAreaPosList.stream()
                                .map(t -> new Point(t.getPosx(), t.getPosy()))
                                .collect(Collectors.toList());

                        for (RobotMapPos pos : mapPos) {
                            Point point = new Point(pos.getPosX(), pos.getPosY());
                            boolean inPolygon = CalculateUtil.isPtInPoly(point, polygon);
                            if (inPolygon) {
                                chargingPos.set(pos);
                                break; // Found the charging position, no need to check further
                            }
                        }
                    }

                    log.info("Selected charging position: {}", chargingPos);

                    if (chargingPos.get() != null) {
                        //
                        if (dispatchService.go2TargetPosition(chargingPos.get(), true)) {
                            robot.setWorkStatus(WorkStatusEnum.WAY_2_CHARGE.getCode());
                            robotService.updateById(robot);
                        }
                    } else {
                        AddWarningDto addWarningDto = new AddWarningDto();
                        addWarningDto.setCode("0");
                        addWarningDto.setTitle("调度告警");
                        addWarningDto.setContent("未配置充电区域");
                        addWarningDto.setSuggestion("请检查充电区域是否正确");
                        addWarningDto.setLevel(0);
                        SpringUtil.getApplicationContext().publishEvent(addWarningDto);
                    }
                } else {
                    log.info("Robot is already charging.");
                }
            }
        }


        return true;
    }

}
